import moment from "moment";

/**
 * 时间格式化工具函数
 *
 * 使用示例：
 *
 * // 基础时间格式化
 * formatTime(1640995200000) // "2022-01-01 08:00:00"
 * formatTime(new Date()) // "2024-01-15 14:30:25"
 * formatTime('2022-01-01') // "2022-01-01 00:00:00"
 *
 * // 自定义格式
 * formatTime(1640995200000, 'YYYY/MM/DD') // "2022/01/01"
 * formatTime(1640995200000, 'MM-DD HH:mm') // "01-01 08:00"
 *
 * // 其他格式化函数
 * formatDate(1640995200000) // "2022-01-01"
 * formatTimeOnly(1640995200000) // "08:00:00"
 * formatDateTime(1640995200000) // "01-01 08:00"
 * formatTimeCN(1640995200000) // "2022年01月01日 08:00:00"
 *
 * // 相对时间和判断
 * getRelativeTime(Date.now() - 3600000) // "1小时前"
 * isToday(new Date()) // true
 * isThisWeek(Date.now() - 86400000) // true
 *
 * // 时长计算
 * getDuration('2022-01-01 08:00:00', '2022-01-01 10:30:00') // 150 (分钟)
 * formatDuration('2022-01-01 08:00:00', '2022-01-01 10:30:00') // "2小时30分钟"
 */

/**
 * 格式化时间戳为标准日期时间格式
 * @param timestamp 时间戳（毫秒）或日期字符串
 * @param format 格式化模板，默认为 'YYYY-MM-DD HH:mm:ss'
 * @returns 格式化后的时间字符串
 */
export const formatTime = (
  timestamp: string | number | Date,
  format = "YYYY-MM-DD HH:mm:ss"
): string => {
  if (!timestamp) return "-";
  return moment(timestamp).format(format);
};

/**
 * 格式化时间戳为日期格式（年-月-日）
 * @param timestamp 时间戳（毫秒）或日期字符串
 * @returns 格式化后的日期字符串
 */
export const formatDate = (timestamp: string | number | Date): string => {
  return formatTime(timestamp, "YYYY-MM-DD");
};

/**
 * 格式化时间戳为时间格式（时:分:秒）
 * @param timestamp 时间戳（毫秒）或日期字符串
 * @returns 格式化后的时间字符串
 */
export const formatTimeOnly = (timestamp: string | number | Date): string => {
  return formatTime(timestamp, "HH:mm:ss");
};

/**
 * 格式化时间戳为短日期时间格式
 * @param timestamp 时间戳（毫秒）或日期字符串
 * @returns 格式化后的时间字符串
 */
export const formatDateTime = (timestamp: string | number | Date): string => {
  return formatTime(timestamp, "MM-DD HH:mm");
};

/**
 * 格式化时间戳为中文日期时间格式
 * @param timestamp 时间戳（毫秒）或日期字符串
 * @returns 格式化后的时间字符串
 */
export const formatTimeCN = (timestamp: string | number | Date): string => {
  return formatTime(timestamp, "YYYY年MM月DD日 HH:mm:ss");
};

/**
 * 获取相对时间（如：1小时前、3天前等）
 * @param timestamp 时间戳（毫秒）或日期字符串
 * @returns 相对时间字符串
 */
export const getRelativeTime = (timestamp: string | number | Date): string => {
  if (!timestamp) return "-";
  return moment(timestamp).fromNow();
};

/**
 * 判断是否是今天
 * @param timestamp 时间戳（毫秒）或日期字符串
 * @returns 是否是今天
 */
export const isToday = (timestamp: string | number | Date): boolean => {
  if (!timestamp) return false;
  return moment(timestamp).isSame(moment(), "day");
};

/**
 * 判断是否是本周
 * @param timestamp 时间戳（毫秒）或日期字符串
 * @returns 是否是本周
 */
export const isThisWeek = (timestamp: string | number | Date): boolean => {
  if (!timestamp) return false;
  return moment(timestamp).isSame(moment(), "week");
};

/**
 * 获取两个时间之间的时长
 * @param startTime 开始时间
 * @param endTime 结束时间
 * @param unit 单位（'days', 'hours', 'minutes', 'seconds'）
 * @returns 时长数值
 */
export const getDuration = (
  startTime: string | number | Date,
  endTime: string | number | Date,
  unit: "days" | "hours" | "minutes" | "seconds" = "minutes"
): number => {
  if (!startTime || !endTime) return 0;
  const start = moment(startTime);
  const end = moment(endTime);
  return end.diff(start, unit);
};

/**
 * 格式化时长为可读格式
 * @param startTime 开始时间
 * @param endTime 结束时间
 * @returns 格式化的时长字符串（如：2小时30分钟）
 */
export const formatDuration = (
  startTime: string | number | Date,
  endTime: string | number | Date
): string => {
  if (!startTime || !endTime) return "-";

  const start = moment(startTime);
  const end = moment(endTime);
  const duration = moment.duration(end.diff(start));

  const days = Math.floor(duration.asDays());
  const hours = duration.hours();
  const minutes = duration.minutes();

  let result = "";
  if (days > 0) result += `${days}天`;
  if (hours > 0) result += `${hours}小时`;
  if (minutes > 0) result += `${minutes}分钟`;

  return result || "0分钟";
};

/**
 * 人民币金额格式化工具函数
 *
 * 使用示例：
 *
 * // 自动单位转换
 * formatCurrency(1234.56) // "1,234.56元"
 * formatCurrency(12345.67) // "1.23万元"
 * formatCurrency(123456.78) // "12.35万元"
 * formatCurrency(1234567.89) // "123.46万元"
 * formatCurrency(12345678.90) // "1,234.57万元"
 *
 * // 指定单位转换
 * formatCurrencyWithUnit(12345, 'thousand') // "12.35千元"
 * formatCurrencyWithUnit(123456, 'wan') // "12.35万元"
 * formatCurrencyWithUnit(1234567, 'wan', 1) // "123.5万元"
 *
 * // 获取合适的单位
 * getOptimalCurrencyUnit(12345) // "thousand"
 * getOptimalCurrencyUnit(123456) // "wan"
 */

/**
 * 人民币单位配置
 */
const CURRENCY_UNITS = {
  yuan: { value: 1, label: "元", threshold: 0 },
  hundred: { value: 100, label: "百元", threshold: 100 },
  thousand: { value: 1000, label: "千元", threshold: 1000 },
  wan: { value: 10000, label: "万元", threshold: 10000 },
  shiwan: { value: 100000, label: "十万元", threshold: 100000 },
  baiwan: { value: 1000000, label: "百万元", threshold: 1000000 },
  qianwan: { value: 10000000, label: "千万元", threshold: 10000000 },
  yi: { value: 100000000, label: "亿元", threshold: 100000000 },
} as const;

type CurrencyUnit = keyof typeof CURRENCY_UNITS;

/**
 * 根据金额获取最适合的单位
 * @param amount 金额
 * @returns 最适合的单位
 */
export const getOptimalCurrencyUnit = (amount: number): CurrencyUnit => {
  const absAmount = Math.abs(amount);

  if (absAmount >= CURRENCY_UNITS.yi.threshold) return "yi";
  if (absAmount >= CURRENCY_UNITS.qianwan.threshold) return "qianwan";
  if (absAmount >= CURRENCY_UNITS.baiwan.threshold) return "baiwan";
  if (absAmount >= CURRENCY_UNITS.shiwan.threshold) return "shiwan";
  if (absAmount >= CURRENCY_UNITS.wan.threshold) return "wan";
  if (absAmount >= CURRENCY_UNITS.thousand.threshold) return "thousand";
  if (absAmount >= CURRENCY_UNITS.hundred.threshold) return "hundred";

  return "yuan";
};

/**
 * 格式化人民币金额（自动选择合适的单位）
 * @param amount 金额
 * @param precision 小数点位数，默认为2
 * @param showThousandSeparator 是否显示千分位分隔符，默认为true
 * @returns 格式化后的金额字符串
 */
export const formatCurrency = (
  amount: number | string,
  precision = 2,
  showThousandSeparator = true
): string => {
  const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;

  if (isNaN(numAmount)) return "0元";

  const unit = getOptimalCurrencyUnit(numAmount);
  return formatCurrencyWithUnit(
    numAmount,
    unit,
    precision,
    showThousandSeparator
  );
};

/**
 * 格式化人民币金额（指定单位）
 * @param amount 金额
 * @param unit 单位
 * @param precision 小数点位数，默认为2
 * @param showThousandSeparator 是否显示千分位分隔符，默认为true
 * @returns 格式化后的金额字符串
 */
export const formatCurrencyWithUnit = (
  amount: number | string,
  unit: CurrencyUnit,
  precision = 2,
  showThousandSeparator = true
): string => {
  const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;

  if (isNaN(numAmount)) return "0元";

  const unitConfig = CURRENCY_UNITS[unit];
  const convertedAmount = numAmount / unitConfig.value;

  // 格式化数字
  let formattedNumber = convertedAmount.toFixed(precision);

  // 移除末尾的0
  if (precision > 0) {
    formattedNumber = parseFloat(formattedNumber).toString();
  }

  // 添加千分位分隔符
  if (showThousandSeparator) {
    const parts = formattedNumber.split(".");
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    formattedNumber = parts.join(".");
  }

  return formattedNumber + unitConfig.label;
};

/**
 * 格式化人民币金额为简洁形式（智能选择单位，优先使用万、千等大单位）
 * @param amount 金额
 * @param precision 小数点位数，默认为1
 * @returns 格式化后的金额字符串
 */
export const formatCurrencyCompact = (
  amount: number | string,
  precision = 1
): string => {
  const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;

  if (isNaN(numAmount)) return "0元";

  const absAmount = Math.abs(numAmount);

  // 对于大金额，优先使用更大的单位
  let unit: CurrencyUnit;
  if (absAmount >= 100000000) unit = "yi";
  else if (absAmount >= 10000000) unit = "qianwan";
  else if (absAmount >= 1000000) unit = "baiwan";
  else if (absAmount >= 100000) unit = "shiwan";
  else if (absAmount >= 10000) unit = "wan";
  else if (absAmount >= 1000) unit = "thousand";
  else unit = "yuan";

  return formatCurrencyWithUnit(numAmount, unit, precision, false);
};

/**
 * 将金额转换为中文大写
 * @param amount 金额
 * @returns 中文大写金额
 */
export const formatCurrencyToChinese = (amount: number | string): string => {
  const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;

  if (isNaN(numAmount) || numAmount < 0) return "零元整";

  const digits = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
  const units = ["", "拾", "佰", "仟"];
  const bigUnits = ["", "万", "亿"];

  // 分离整数和小数部分
  const [integerPart, decimalPart] = numAmount.toFixed(2).split(".");

  // 转换整数部分
  let result = "";
  const integerStr = integerPart.padStart(
    Math.ceil(integerPart.length / 4) * 4,
    "0"
  );

  for (let i = 0; i < integerStr.length; i += 4) {
    const section = integerStr.slice(i, i + 4);
    const sectionNum = parseInt(section, 10);

    if (sectionNum !== 0) {
      let sectionStr = "";
      for (let j = 0; j < 4; j++) {
        const digit = parseInt(section[j], 10);
        if (digit !== 0) {
          sectionStr += digits[digit] + units[3 - j];
        } else if (sectionStr && j < 3 && parseInt(section[j + 1], 10) !== 0) {
          sectionStr += "零";
        }
      }

      const bigUnitIndex = Math.floor((integerStr.length - i - 4) / 4);
      result += sectionStr + (bigUnits[bigUnitIndex] || "");
    }
  }

  result = result || "零";
  result += "元";

  // 处理小数部分
  if (decimalPart && parseInt(decimalPart, 10) > 0) {
    const jiao = parseInt(decimalPart[0], 10);
    const fen = parseInt(decimalPart[1], 10);

    if (jiao > 0) {
      result += digits[jiao] + "角";
    }
    if (fen > 0) {
      result += digits[fen] + "分";
    }
  } else {
    result += "整";
  }

  return result;
};
